﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace RM.Data
{
    public class EfRespository<T>:IRespository<T> 
        where T:class
    {
        private readonly IUnitOfWork _unitOfWork;
        internal DbSet<T> dbSet;
        public IUnitOfWork UnitOfWork { get { return _unitOfWork; } }
        internal DbContext Database { get { return _unitOfWork.Db; } }

        public virtual IQueryable<T> Table
        {
            get
            {
                return this.dbSet;
            }
        }

        public EfRespository()
        {
            _unitOfWork = new UnitOfWork();
            dbSet = _unitOfWork.Db.Set<T>();
        }

        public EfRespository(IUnitOfWork unitOfWork)
        {
            if (unitOfWork == null)
                throw new ArgumentException("unitOfWork");
            _unitOfWork = unitOfWork;
            dbSet = _unitOfWork.Db.Set<T>();
        }

        public IEnumerable<T> Get(Expression<Func<T, bool>> filter = null,
            Func<IQueryable<T>, IOrderedEnumerable<T>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<T> query = dbSet;
            if (filter != null)
            {
                query = query.Where(filter);
            }
            foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }
            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            return query.ToList();
        }

        public T Single(object primaryKey)
        {
            return dbSet.Find(primaryKey);
        }

        public Dictionary<string, string> GetAuditNames(dynamic dynamicObject)
        {
            throw new NotImplementedException();
        }

        public T SingleOrDefault(object primaryKey)
        {
            return dbSet.Find(primaryKey);
        }

        public IEnumerable<T> GetAll()
        {
            return dbSet.AsEnumerable().ToList();
        }

        public bool Exists(object primaryKey)
        {
            return dbSet.Find(primaryKey) != null;
        }

        public int Insert(T entity)
        {
            dynamic obj = dbSet.Add(entity);
            _unitOfWork.Db.SaveChanges();
            return obj.Id;
        }

        public void Update(T entity)
        {
            dbSet.Attach(entity);
            _unitOfWork.Db.Entry(entity).State = EntityState.Modified;
            _unitOfWork.Db.SaveChanges();
        }

        public int Delete(T entity)
        {
            if (_unitOfWork.Db.Entry(entity).State == EntityState.Detached)
            {
                dbSet.Attach(entity);
            }
            dynamic obj = dbSet.Remove(entity);
            _unitOfWork.Db.SaveChanges();
            return obj.Id;
        }
    }
}
